package cc.wanforme.fsync.config.restUpload;

import cc.wanforme.fsync.server.ServerProperty;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.io.Resource;
import org.springframework.http.HttpOutputMessage;
import org.springframework.http.client.ClientHttpRequestFactory;
import org.springframework.http.converter.*;
import org.springframework.web.client.RestTemplate;

import java.io.IOException;
import java.io.InputStream;
import java.nio.charset.Charset;
import java.util.ArrayList;
import java.util.List;

/**
 * @see <a href="https://github.com/spring-attic/spring-android/issues/35">参考</a>
 */
@Configuration
public class UploadRestTemplateConfig {


    @Bean("uploadRestTemplate")
    public RestTemplate uploadRestTemplate(ClientHttpRequestFactory factory,  ServerProperty serverProperty) {
        RestTemplate restTemplate = new RestTemplate(factory);
        // 支持中文编码
        restTemplate.getMessageConverters().set(1, new StringHttpMessageConverter(Charset.forName("UTF-8")));
        restTemplate.getMessageConverters().add(0,
                new CallbackFormHttpMessageConverter(serverProperty.getSendBufferSize()));
        return restTemplate;
    }


    // 重写 form表单消息转换器
    public static class CallbackFormHttpMessageConverter extends FormHttpMessageConverter {

        public CallbackFormHttpMessageConverter(int bufferSize) {
            super();

			final List<HttpMessageConverter<?>> partConverters = new ArrayList<>();
			partConverters.add(new CallbackResourceHttpMessageConverter(bufferSize));

            // Continue to add in default for FormHttpMessageConverter.
			partConverters.add(new ByteArrayHttpMessageConverter());
			final StringHttpMessageConverter stringHttpMessageConverter = new StringHttpMessageConverter();
			stringHttpMessageConverter.setWriteAcceptCharset(false);
			partConverters.add(stringHttpMessageConverter);
			partConverters.add(new ResourceHttpMessageConverter());
			setPartConverters(partConverters);

            // not work!
//            List<HttpMessageConverter<?>> partConverters = new ArrayList<>(getPartConverters());
//            partConverters.add(new CallbackResourceHttpMessageConverter(callback));
//            setPartConverters(partConverters);
        }
    }

    // 重写 resource 表单消息转换器
    public static class CallbackResourceHttpMessageConverter extends ResourceHttpMessageConverter {

        private final int bufferSize ; // = StreamUtils.BUFFER_SIZE;
        public CallbackResourceHttpMessageConverter(int bufferSize) {
            this.bufferSize = bufferSize;
        }

        @Override
        protected void writeInternal(final Resource resource, final HttpOutputMessage outputMessage)
                throws IOException, HttpMessageNotWritableException {

            Long id = null;
            if( resource instanceof IDFileSystemResource idResource) {
                id = idResource.getID();
                //System.out.println("id >> " + id);
            }

            try (InputStream in = resource.getInputStream()) {
                final long fileSize = resource.contentLength();
                final byte[] buffer = new byte[bufferSize];

                long count = 0;
                int n ;
                int percentage ;
                while (-1 != (n = in.read(buffer))) {
                    outputMessage.getBody().write(buffer, 0, n);
                    count += n;
                    percentage = (int) ((count * 100) / fileSize);

                    if(id != null) {
                        SimpleProgressTracker callback = UploadProgressCenter.getOrDefault(id, fileSize);
                        callback.trackProgress(percentage, count);
                    }
                }
            }
            outputMessage.getBody().flush();
        }
    }

}
